package com.wbc.demo.CompletableFutureDemo;

import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;


/**
 * 异步处理等待最后一个完成
 * 一个接口返回结果需要几个方法同时完成之后才可以继续，并且这几个方法执行没有先后顺序，可以使用本Demo
 */
public class CompletableFutureDemo1 {


    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //创建一个自定义的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        AtomicReference<String> str = new AtomicReference();
        System.out.println("开始一部");
        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(
                CompletableFuture.runAsync(() -> {
                    try {
                        Thread.sleep(500000);
                        str.set("99");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }),
                CompletableFuture.runAsync(() -> {
                    str.set("66");
                })
        );
        objectCompletableFuture.join();
        System.out.println(str.get());



        //定义个返回结果集
        Map<String,Object> result = new ConcurrentHashMap<>();
        //记录程序开始运行的时间戳 毫秒
        long start = System.currentTimeMillis();
        System.out.println("start:"+start);


//        completableFuture1(result);

//        completableFuture2(result,executorService);

        completableFuture3(result,executorService);

        executorService.shutdown();
        //记录程序结束运行的时间戳 毫秒
        long end = System.currentTimeMillis();
        System.out.println("use:"+(end-start)); //计算运行时间

        System.out.println("结束");

    }

    private static void completableFuture3(Map<String, Object> result, Executor threadPool) {
        /****************************************** 异步同时执行 有返回值 *************************************/

        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return selectData1();
        }, threadPool).thenCombine(CompletableFuture.supplyAsync(() -> {
            return selectData2();
        }, threadPool), new BiFunction<Object, Object, Object>() {
            @Override
            public Object apply(Object o, Object o2) {
                //这里写逻辑
                System.out.println("结果一：" + o);
                System.out.println("结果二：" + o2);
                return o.toString() + o2.toString();
            }
        });
        Object o = null;
        try {
            o = objectCompletableFuture.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(o);
        /****************************************** 异步同时执行 有返回值*************************************/

    }

    private static void completableFuture2(Map<String, Object> result, Executor threadPool) {
        /****************************************** 异步同时执行 无返回值 *************************************/
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(
                CompletableFuture.runAsync(() -> {
                    result.put("key1", selectData1()); //执行方法 selectData1
                }, threadPool),
                CompletableFuture.runAsync(() -> {
                    result.put("key2", selectData2()); //执行方法 selectData2
                }, threadPool),
                CompletableFuture.runAsync(() -> {
                    result.put("key3", selectData3());//执行方法 selectData3
                }, threadPool)
        );
        voidCompletableFuture.join();
        /****************************************** 异步同时执行 无返回值*************************************/

    }

    private static void completableFuture1(Map<String, Object> result) {

        /****************************************** 正常顺序执行 *************************************/
        result.put("key1", selectData1());//执行方法 selectData1
        result.put("key2", selectData2());//执行方法 selectData2
        result.put("key3", selectData3());//执行方法 selectData3
        /****************************************** 正常顺序执行 *************************************/
    }

    private static Object selectData1() {
        System.out.println("执行：selectData1");
        sleep(3000);
        System.out.println("结束：selectData1");
        return "value1";
    }


    private static Object selectData2() {
        System.out.println("执行：selectData2");
        sleep(1000);
        System.out.println("结束：selectData2");
        return "value2";
    }

    private static Object selectData3() {
        System.out.println("执行：selectData3");
        sleep(1500);
        System.out.println("结束：selectData3");
        return "value3";
    }

    private static void sleep(int i) {
        try {
            Thread.sleep(i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


}

